// code 3 thread: lock 临界区 临界资源
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
using namespace std;
//临界资源 能被多个执行流访问的资源
int tickets = 10000;
//互斥锁
pthread_mutex_t ticket_mutex;
void *thread_todo_func(void *arg)
{
    string name(static_cast<char *>(arg));
    //抢票
    while (1)
    {
        //临界区 访问临界资源的代码段
        //若不加锁 导致数据不一致的问题:本来10000票,抢走超过10000张,抢走的编号一致...
        //判断ticket>0 1.lode到寄存器 2. tickets -0 3.判断是否为真
        //可能在1后被切走, 然后另一线程--,在被切回来票数就为负了
        //加互斥锁,保证对临界资源的操作是原子的:要么没做,要么做完了
        //互斥锁本身也是临界资源,当自身实现保证了原子性!

        //阻塞式申请锁
        //对临界区加锁,粒度越细越好,提高效率,并发率
        pthread_mutex_lock(&ticket_mutex);
        if (tickets > 0)
        {
            usleep(1000);
            //tickets--: 1.lode到寄存器 2.-- 3.写回内存
            //有可能在2.时被切走其他线程在时间片内循环执行123, 等这个再切回来执行3票就多了
            cout << name << " 抢到票 编号: " << tickets--<<endl;
            //解锁
            pthread_mutex_unlock(&ticket_mutex);
        }
        else
        {
            cout << name << " 抢票失败,没有票了..." << endl;
            //解锁 确保条路径都能正确解锁,否则可能造成死锁问题,其他线程一直阻塞申请锁!
            pthread_mutex_unlock(&ticket_mutex);
            break;
        }
    }
}

int main()
{
    //保存线程用户级id
    pthread_t tid_1;
    pthread_t tid_2;
    pthread_t tid_3;
    pthread_t tid_4;

    //初始化互斥锁
    pthread_mutex_init(&ticket_mutex,nullptr);

    if (!pthread_create(&tid_1, nullptr, thread_todo_func, (void *)"thread_1") &&
        !pthread_create(&tid_2, nullptr, thread_todo_func, (void *)"thread_2") &&
        !pthread_create(&tid_3, nullptr, thread_todo_func, (void *)"thread_3") &&
        !pthread_create(&tid_4, nullptr, thread_todo_func, (void *)"thread_3"))
        cout << "创建线程成功!" << endl;
    else
        return errno;

    //等待线程退出
    int join_ret = pthread_join(tid_1, nullptr);
    cout << strerror(join_ret) << endl;
    join_ret = pthread_join(tid_2, nullptr);
    cout << strerror(join_ret) << endl;
    join_ret = pthread_join(tid_3, nullptr);
    cout << strerror(join_ret) << endl;
    join_ret = pthread_join(tid_4, nullptr);
    cout << strerror(join_ret) << endl;

    //释放互斥锁
    pthread_mutex_destroy(&ticket_mutex);

    cout << "进程退出" << endl;
    return 0;
}